function h = feature_extractor(data, type, param)
%FEATURE_EXTRACTOR
%called "hist_proc" in older version

%% pre-process input data, e.g. abs, diff, predict-error
if param.use_abs
    data = abs(data);
end
if param.diff_first
for i = 1:param.diff_n
    % diff(data, distance, direction);
    switch lower(param.diff_dir)
        case 'x'
            data = diff(data, param.diff_dis, 2);
        case 'y'
            data = diff(data, param.diff_dis, 1);
    end
end
end
if isa(param.pe_func, 'function_handle')
    for i = 1:param.pe_n
        data = param.pe_func(data);
    end
end
if ~param.diff_first
for i = 1:param.diff_n
    % diff(data, distance, direction);
    switch lower(param.diff_dir)
        case 'x'
            data = diff(data, param.diff_dis, 2);
        case 'y'
            data = diff(data, param.diff_dis, 1);
    end
end
end

%% type-specific processing
switch lower(type)
    case 'hist'
        switch lower(param.space)
            case 'dct'
                h = generateHist(data, param.threshold);
            case 'grey' %ignore threshold
                h = generateHist(data, 255, 0);
            case 'color' %ignore threshold
                if size(data, 3) == 1
                    h1 = generateHist(data, 255, 0);
                    h = [h1, h1, h1];
                else
                    h = [generateHist(data(:,:,1), 255, 0), generateHist(data(:,:,2), 255, 0), generateHist(data(:,:,3), 255, 0)];
                end
            otherwise
                error('hist_proc:hist:UnknownSpace','Unknown value for space: %s.', param.space);
        end
    case 'colorhist'
        h = generateColorHist(data);
    case 'colorhist2'
        h = generateColorHist(data, 10);
    case 'blockhist'
        col = size(param.points, 2);
        [M,N] = size(data);
        h = [];
        for i = 1:col
            single_coef = data(param.points(1, i):8:M, param.points(2, i):8:N);
            h = [h,generateHist(single_coef, param.threshold)];
        end
    case 'markov'
        h1 = generateHist2D(data, param.threshold, 'h');
        h2 = generateHist2D(data, param.threshold, 'v');
        %h = [h1(:);h2(:)];
        h3 = generateHist2D(data, param.threshold, 'm');
        h4 = generateHist2D(data, param.threshold, 'r');
        h = [h1(:);h2(:);h3(:);h4(:)]';
    case 'point-diff-markov'
        h = [];
    case 'markov2-noncausal'
        h = markov2_noncausal_new_fast(data, param.threshold);
        h = h(:);
    case 'markov2-noncausal-dct'
        h = markov2_noncausal_new_fast(data, param.threshold);
        h = h(:);
    case 'diff-markov'
        h = generateDiff2DHist(data, param.threshold, 0);
    case 'abs-diff-markov'
        h = generateDiff2DHist(data, param.threshold, 1);
    case 'moment'
        h = moment(data, order);
    case 'ccpev-274' %data is filename
        fs = ccpev548(data, param.qf);
        h = fs(1:274)-fs(275:548);
    case 'ccpev-548' %data is filename
        h = ccpev548(data, param.qf);
    case 'lbp-test'
        MAPPING = getmapping(8, 'u2');
        h = lbp(data, 1, 8, MAPPING, 'other');
        h = markov(h, [0 58], 'x', 2);
        h = h(:);
    case 'lbp-test2'
        MAPPING = getmapping(8, 'riu2');
        h = lbp(data, 1, 8, MAPPING, 'other');
        h = markov(h, [0 9], 'x', 2);
        h = h(:);
    case 'lbp_u2(8,1)'
        MAPPING = getmapping(8, 'u2');
        h = lbp(data, 1, 8, MAPPING, 'nh');
    case 'lbp_u2(8,1-3)'
        MAPPING = getmapping(8, 'u2');
        h = [lbp(data, 1, 8, MAPPING, 'nh'), lbp(data, 2, 8, MAPPING, 'nh'), lbp(data, 3, 8, MAPPING, 'nh')];
    case 'median_f'
        h = median_features(data);
    case 'markovn_f'
        h = markovneighbor_features(data);
    case 'clique_f'
        h = clique_features(data);
    case 'lawsmask_f'
        h = lawsmask_features(data);
    case 'lbppe_f'
        h = lbppe_features(data);
    case 'varpe_f'
        h = varpe_features(data);
    case 'lbp'
        h = lbp(data, param.radius, param.neighbors, 0, 'nh');
    case 'hist-entropyfilt'
        J = entropyfilt(data);
        h = histall(J, param.threshold);
    case 'hist-rangefilt'
        J = entropyfilt(data);
        h = histall(J, param.threshold);
    case 'hist-stdfilt'
        J = stdfilt(data);
        h = histall(J, param.threshold);
    case 'gabor'
        h = gabortest3(data);
    case 'lpq'
        h = lpq(data, 3, 1);
    case 'ltp'
        h = ltp(data, 1, 8, param.threshold, 0, 'nh');
    case 'wld'
        h = WLD_new(data);
    case 'iflt'
        h = iflt_fast(data, 8, 1);
        h = h(:);
    case 'iflt2'
        h = iflt_fast(data,[1,1;1,0;1,-1;0,-1;0,1;-1,1;-1,0;-1,-1]);
        h = h(:);
    case 'ldp'
        h = ldp(data, 'sh');
    case 'dlbp'
        h = DLBP(data, param.radius, param.neighbors, param.k_ratio);
    case 'dlbpk'
        h = DLBPk(data, param.radius, param.neighbors, param.mapping);
    case 'lfd_c1'
        [h1, ~] = LFD_C(data, param.radius, param.neighbors, param.Q, param.rng);
        h = h1(:);
    case 'lfd_c2'
        [~, h2] = LFD_C(data, param.radius, param.neighbors, param.Q, param.rng);
        h = h2(:);
    case 'locp'
        h = locp(data, param.radius, param.neighbors, 'nh');
    otherwise
        error('hist_proc:type:UnknownType','Unknown value of type: %s.', lower(type));
end
end %feature_extractor
